import { FrontProcessing } from "..";
import { debounce } from "stl-typescript";
import { TPoint } from "../Actors/TMeshPoint";

interface IMouseEvent {
  clientX: any;
  clientY: any;
  preventDefault(): void;
}
/**
 * @param firstEnter  鼠标是否是第一次点击
 * 当firstEnter为true时，表示鼠标第一次点击，此时需要获取鼠标点击位置，作为框线的左上点，
 * firstEnter为false时，表示鼠标第二次点击鼠标第二次点击，表示鼠标第二次点击，此时需要获
 * 取鼠标点击位置，作为框线的右下点
 */
export class SelectBoxComp {
  parent: FrontProcessing;
  selectBox: HTMLElement;
  canvasDom: HTMLElement;
  downX: number | undefined;
  downY: number | undefined;
  firstEnter = true;
  selectedPoints: TPoint[]; // 注：此处表示已经被选择的网格点，包含所有方式（点选和框选）
  mouseDownHandler!: {
    (event: IMouseEvent): void;
    (this: HTMLElement, ev: MouseEvent): any;
  };
  mouseMoveHandler!: {
    (event: {
      /* __placeholder__ */
      clientX: number;
      /* __placeholder__ */
      clientY: number;
    }): void;
    (this: HTMLElement, ev: MouseEvent): any;
  };
  mouseUpHandler!: {
    (event: {
      /* __placeholder__ */
      clientX: number;
      /* __placeholder__ */
      clientY: number;
    }): void;
    (this: HTMLElement, ev: MouseEvent): any;
  };

  constructor(
    parent_ins: FrontProcessing,
    selectBox_ins: HTMLElement,
    canvasDom_ins: HTMLElement
  ) {
    this.parent = parent_ins;
    this.selectBox = selectBox_ins;
    this.canvasDom = canvasDom_ins;
    this.selectedPoints = [];
  }

  // 启动框选
  enableSelectByBox(type: string) {
    this.shrinkBox(this.selectBox);
    this.mouseDownHandler = this.handleMouseDown(type);
    if (this.mouseDownHandler) {
      this.canvasDom.removeEventListener("contextmenu", this.mouseDownHandler);
    }
    this.canvasDom.addEventListener("contextmenu", this.mouseDownHandler);
  }

  // 关闭框选效果
  disableSelectBox() {
    this.shrinkBox(this.selectBox);
    this.firstEnter = true; // 恢复默认值
    if (this.mouseDownHandler) {
      this.canvasDom.removeEventListener("contextmenu", this.mouseDownHandler);
    }
    if (this.mouseMoveHandler) {
      this.canvasDom.removeEventListener("mousemove", this.mouseMoveHandler);
    }
    if (this.mouseUpHandler) {
      this.canvasDom.removeEventListener("mouseup", this.mouseUpHandler);
    }
  }

  // 鼠标点击出现选择框
  handleMouseDown(type: string) {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const that = this;
    return function (event: IMouseEvent) {
      event.preventDefault();
      if (!that.firstEnter) {
        that.firstEnter = true;
        // 不显示选择框
        if (that.selectBox) {
          that.shrinkBox(that.selectBox);
        }
        if (that.mouseMoveHandler) {
          document.body.removeEventListener("mousemove", that.mouseMoveHandler);
        }
        if (that.mouseDownHandler) {
          document.body.removeEventListener(
            "contextmenu",
            that.mouseDownHandler
          );
        }
        return;
      }

      // 第一次进入该函数
      that.firstEnter = false;
      // 显示选择框
      that.downX = event.clientX;
      that.downY = event.clientY;
      if (that.selectBox) {
        that.shrinkBox(that.selectBox);
        that.selectBox.style.left = that.downX + "px";
        that.selectBox.style.top = that.downY + "px";

        // 鼠标拖动效果设置
        // 1. 取消原来的鼠标移动事件
        if (that.mouseMoveHandler) {
          document.body.removeEventListener("mousemove", that.mouseMoveHandler);
        }
        // 2. 根据不同的type选择不同的鼠标移动事件
        if (type === "mesh") {
          that.mouseMoveHandler = that.handleMouseMoveToMesh();
        } else if (type === "meshPoint") {
          that.mouseMoveHandler = that.handleMouseMoveToMeshPoint();
        } else {
          that.mouseMoveHandler = that.handleMouseMove();
        }
        document.body.addEventListener("mousemove", that.mouseMoveHandler);

        // 鼠标抬起效果设置
        if (!that.mouseUpHandler) {
          that.mouseUpHandler = that.handleMouseUp();
        }
        document.body.addEventListener("mouseup", that.mouseUpHandler);
      }
    };
  }

  // 鼠标移动
  handleMouseMove() {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const that = this;
    const func_compute_selected = debounce(
      (event: { x: number; y: number; width: number; height: number }) => {
        // [x, y, width, height]
        that.parent.meshComp.selectElementsByBox(
          event.x,
          event.y,
          event.width,
          event.height,
          that.canvasDom.clientHeight
        );
      },
      25,
      false
    );
    return function (event: { clientX: number; clientY: number }) {
      // 1. 设置选择框
      const selectBox = that.selectBox;
      const downX = that.downX;
      const downY = that.downY;
      if (!downX || !downY) return;
      const x = Math.min(event.clientX, downX);
      selectBox.style.left = x + "px";
      const y = Math.min(event.clientY, downY);
      selectBox.style.top = y + "px";
      const width = Math.abs(downX - event.clientX);
      selectBox.style.width = width + "px";
      const height = Math.abs(downY - event.clientY);
      selectBox.style.height = height + "px";

      func_compute_selected({ x: x, y: y, width: width, height: height });
    };
  }

  // 在鼠标移动中选中选择框覆盖的网格
  handleMouseMoveToMesh() {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const that = this;
    const func_compute_selected = debounce(
      (event: { x: number; y: number; width: number; height: number }) => {
        // [x, y, width, height]
        that.parent.meshComp.selectElementsByBox(
          event.x,
          event.y,
          event.width,
          event.height,
          that.canvasDom.clientHeight
        );
      },
      25,
      false
    );
    return function (event: { clientX: number; clientY: number }) {
      // 1. 设置选择框
      const selectBox = that.selectBox;
      const downX = that.downX;
      const downY = that.downY;
      if (!downX || !downY) return;
      const x = Math.min(event.clientX, downX);
      selectBox.style.left = x + "px";
      const y = Math.min(event.clientY, downY);
      selectBox.style.top = y + "px";
      const width = Math.abs(downX - event.clientX);
      selectBox.style.width = width + "px";
      const height = Math.abs(downY - event.clientY);
      selectBox.style.height = height + "px";

      func_compute_selected({ x: x, y: y, width: width, height: height });
    };
  }
  // 在鼠标移动中选中选择框覆盖的网格交叉点
  handleMouseMoveToMeshPoint() {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const that = this;
    const func_compute_selected_mesh_point = debounce(
      (event: { x: number; y: number; width: number; height: number }) => {
        // [x, y, width, height]
        that.parent.meshComp.selectMeshPointByBox(
          event.x,
          event.y,
          event.width,
          event.height,
          that.canvasDom.clientHeight
        );
      },
      25,
      false
    );
    return function (event: { clientX: number; clientY: number }) {
      // 1. 设置选择框
      const selectBox = that.selectBox;
      const downX = that.downX;
      const downY = that.downY;
      if (!downX || !downY) return;
      const x = Math.min(event.clientX, downX);
      selectBox.style.left = x + "px";
      const y = Math.min(event.clientY, downY);
      selectBox.style.top = y + "px";
      const width = Math.abs(downX - event.clientX);
      selectBox.style.width = width + "px";
      const height = Math.abs(downY - event.clientY);
      selectBox.style.height = height + "px";
      func_compute_selected_mesh_point({
        x: x,
        y: y,
        width: width,
        height: height,
      });
    };
  }

  // 鼠标放开
  handleMouseUp() {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const that = this;
    return function () {
      // 不显示选择框
      if (that.selectBox) {
        that.shrinkBox(that.selectBox);
      }
      if (that.mouseMoveHandler) {
        document.body.removeEventListener("mousemove", that.mouseMoveHandler);
      }
      if (that.mouseUpHandler) {
        document.body.removeEventListener("mouseup", that.mouseUpHandler);
      }
    };
  }

  // 将box设置为一个点
  shrinkBox(selectBox: HTMLElement) {
    selectBox.style.width = "0px";
    selectBox.style.height = "0px";
  }

  // 重置选中的网格点
  resetSelectedMeshPoint() {
    this.parent.meshComp.selectMeshPointByClick(this.selectedPoints);
  }

  // 清除网格选中节点
  clearSelectedPoints() {
    this.selectedPoints = [];
  }
}
